﻿#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<vector>
#include<string>
#include<list>
#include<algorithm>
using namespace std;


//1. list的介绍及使用 

//1.1 list的介绍

//1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器，并且该容器可以前后双向迭代。
//2. list的底层是双向链表结构，双向链表中每个元素存储在互不相关的独立节点中，在节点中通过指针指向
//其前一个元素和后一个元素。
//3. list与forward_list非常相似：最主要的不同在于forward_list是单链表，只能朝前迭代，已让其更简单高效。
//4. 与其他的序列式容器相比(array，vector，deque)，list通常在任意位置进行插入、移除元素的执行效率更好。
//5. 与其他序列式容器相比，list和forward_list最大的缺陷是不支持任意位置的随机访问，比如：要访问list
//的第6个元素，必须从已知的位置(比如头部或者尾部)迭代到该位置，在这段位置上迭代需要线性的时间
//开销；list还需要一些额外的空间，以保存每个节点的相关联信息(对于存储类型较小元素的大list来说这
//可能是一个重要的因素)

//1.2 list的使用 

//list中的接口比较多，此处类似，根据前面所学的string和vector，我们可以进行初步的使用list
void test_list1()
{
	//创建一个int的list对象，并尾插数据
	list<int> l1;
	l1.push_back(34);
	l1.push_back(31);
	l1.push_back(32);
	l1.push_back(35);
	l1.push_back(38);
	//遍历（注意：list不能使用[ ]进行访问了，list使用迭代器和范围for遍历）
	list<int>::iterator it1 = l1.begin();
	while (it1 != l1.end())
	{
		cout << *it1 << endl;
		++it1;
	}
	cout << endl;
	//范围for遍历
	for (auto element1 : l1)
	{
		cout << element1 << " ";
	}
	cout << endl;
}


//以下为list中一些常见的重要接口。

//1.2.1 list的构造

//构造函数（ (constructor)）                                 接口说明
//list(size_type n, const value_type& val = value_type()) 构造的list中包含n个值为val的元素
//list()                                                    构造空的list
//list(const list& x)                                       拷贝构造函数
//list(InputIterator ﬁrst, InputIterator last)        用[ﬁrst, last)区间中的元素构造list


//1.2.2 list iterator的使用

//函数声明                                                  接口说明
//begin +end                      返回第一个元素的迭代器 + 返回最后一个元素下一个位置的迭代器
//rbegin +rend                 返回第一个元素的reverse_iterator, 即end位置，返回最后一个元素下一个位置的reverse_iterator, 即begin位置

void test_list2()
{
	list<int> lt;
	//尾插数据
	lt.push_back(1);
	lt.push_back(2);
	lt.push_back(3);
	lt.push_back(4);

	//头插数据
	lt.push_front(10);
	lt.push_front(20);
	lt.push_front(30);
	lt.push_front(40);

	//迭代器打印
	list<int>::iterator it = lt.begin();
	while (it != lt.end())
	{
		cout << *it << " ";
		++it;
	}
	cout << endl;
}
//【注意】
//1. begin与end为正向迭代器，对迭代器执行++操作，迭代器向后移动
//2. rbegin(end)与rend(begin)为反向迭代器，对迭代器执行++操作，迭代器向前移动
  
//1.2.3 list容器

//函数声明                                                  接口说明
//empty                                   检测list是否为空，是返回true，否则返回false
//size                                               返回list中有效节点的个数

//1.2.4 list 元素接口

//函数声明                                      接口说明
//front                             返回list的第一个节点中值的引用
//back                             返回list的最后一个节点中值的引用

//1.2.5 list增删查改

//函数声明                                    接口说明
//push_front                    在list首元素前插入值为val的元素
//pop_front                              删除list中第一个元素
//push_back                          在list尾部插入值为val的元素
//pop_back                             删除list中最后一个元素
//insert                        在list position 位置中插入值为val的元素
//erase                              删除list position位置的元素
//swap                               交换两个list中的元素
//clear                                 清空list中的有效元素

//注意：list和vector都没有提供find了，因为find被直接放到了算法里，通过迭代器实现
void test_list3()
{
	list<int> lt1;
	lt1.push_back(3);
	lt1.push_back(5);
	lt1.push_back(7);
	lt1.push_back(9);
	for (auto element : lt1)
	{
		cout << element << " ";
	}
	cout << endl;

	//在第三个位置插入一个数字100(insert)
	//不能像以前vector一样使用迭代器直接插入了
	list<int>::iterator it = lt1.begin();
	for (size_t i = 0; i < 3; ++i)
	{
		++it;
	}
	lt1.insert(it, 100);
	for (auto element : lt1)
	{
		cout << element << " ";
	}
	cout << endl;

	//用find查找9的位置
	list<int>::iterator init = lt1.begin();
	auto pos = find(init, lt1.end(), 9);
	if (pos != lt1.end())
	{
		cout << *pos;
		//9之前插入30
		lt1.insert(pos, 30);
	}
	for (auto element : lt1)
	{
		cout << element << " ";
	}
	cout << endl;
}

//1.2.6 list操作

//函数声明                                    接口说明
//reverse                                     逆置list
//sort                                      对list进行排序
//merge                                   对两个list进行归并
//unique                                  对链表去重（前提是有序）
//remove                           就是找到这个位置，并删除（相当于find+erase）
//splice                               把一个list的内容直接转移到另外一个

void test_list4()
{
	list<int> lt1;
	lt1.push_back(3);
	lt1.push_back(67);
	lt1.push_back(7);
	lt1.push_back(9);
	for (auto element : lt1)
	{
		cout << element << " ";
	}
	cout << endl << "逆置后:";
	reverse(lt1.begin(), lt1.end());
	for (auto element : lt1)
	{
		cout << element << " ";
	}
	cout << endl;
	//对list排序只能使用list的sort
	lt1.sort();
	for (auto element : lt1)
	{
		cout << element << " ";
	}
	cout << endl;

	int begin = clock();
	//由于list的sort效率较低，所以可以把list的数据拷贝到vector排完序在拷贝回去
	list<int> lt2;
	vector<int> v;
	srand((size_t)time(0));
	int n = 100000;
	for (size_t i = 0; i < n; i++)
	{
		lt2.push_back(rand());
	}
	//把list产生的数拷贝到vector
	for (auto element : lt2)
	{
		v.push_back(element);
	}
	//排序
	sort(v.begin(), v.end());
	//把vector的数据拷贝回list
	size_t i = 0;
	for (auto& element : lt2)
	{
		element = v[i++];
	}
	int end = clock();
	cout << "sort:" << end - begin << "ms" << endl;

	int arr[] = { 34,12,34,67 };
	list<int> lt3(arr, arr + sizeof(arr) / sizeof(arr[0]));
	lt3.remove(34);
	lt3.remove(2300);
	for (auto e : lt3)
	{
		cout << e << " ";
	}
	cout << endl;
}
//注意：remove如果没找到也不会报错，只会上面都不做

//1.2.7 list的迭代器失效

//迭代器失效即迭代器所指向的节点的无效，即该节点被删除了。
//因为list的底层结构为带头结点的双向循环链表，因此在list中进行插入时是不会导致list的迭代
//器失效的，只有在删除时才会失效，并且失效的只是指向被删除节点的迭代器，其他迭代器不会受到影响，
//也就是说list下list的insert不会造成迭代器失效，而erase会造成迭代器失效

void test_list5()
{
	int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
	list<int> l(array, array + sizeof(array) / sizeof(array[0]));

	auto it = l.begin();
	while (it != l.end())
	{
		// erase()函数执行后，it所指向的节点已被删除，因此it无效，在下一次使用it时，必须先给其赋值
		l.erase(it);
		++it;//迭代器已经失效
	}
}

//1.2.8 迭代器的划分（按照性质划分）
//三种划分由容器的底层结构决定
//1.单向迭代器（++）：forward_list/unordered_xxx
//2.双向（++/--):list/map/set
//3.随机(++/--/+/-):vector/string/deque